import numpy as np


class calc_p(object):
    def __init__(self, n: int) -> None:
        self.n = n

    def calc(self) -> float:
        """
        模拟计算Π 10 ** 7 以下很快
        """
        x = np.sqrt(  # 求距离
            np.sum(  # 求每组点与点(0.5, 0.5)的差的平方的和
                np.square(
                    np.random.rand(  # 得到n组2维的点
                        self.n, 2
                    ) - 0.5
                ),
                axis=1
            )
        )
        return len(  # 得到小于等于0.5的点的个数
            np.extract(x <= 0.5, x)
        ) / self.n / 0.25

    def calc_2(self) -> float:
        """
        模拟计算Π 无限制 但是慢
        """
        s = 0
        for i in range(self.n):
            if np.linalg.norm(np.random.rand(2) - 0.5) <= 0.5:
                s += 1
        return s / self.n / 0.25

    def calc_3(self) -> float:
        """
        模拟计算Π 10 ** 7 以上也可以算
        """
        rn = int(self.n / 10 ** 7)
        c = 0
        for i in range(rn):
            x = np.sqrt(  # 求距离
                np.sum(  # 求每组点与点(0.5, 0.5)的差的平方的和
                    np.square(
                        np.random.rand(  # 得到n组2维的点
                            10 ** 7, 2
                        ) - 0.5
                    ),
                    axis=1
                )
            )
            c += len(  # 得到小于等于0.5的点的个数
                np.extract(x <= 0.5, x)
            )
        return c / self.n / 0.25

if __name__ == '__main__':
    # print(calc_p(10 ** 7).calc())
    # print(calc_p(10 ** 7).calc_2())
    print(calc_p(10 ** 8).calc_3())
